package org.cupk2.service.controller;

import com.cupk2.lucene.impl.Cupk2LuceneSearchImpl;
import com.cupk2.lucene.inter.Cupk2LuceneSearchInter;
import com.cupk2.lucene.query.DocumentQuery;
import com.cupk2.lucene.query.rule.DocumentRuleByMultiField;
import com.cupk2.lucene.query.rule.DocumentRuleByTerm;
import com.cupk2.lucene.query.rule.DocumentRuleByVector;
import com.cupk2.lucene.result.DocumentResult;
import com.cupk2.lucene.utils.CupkLuceneUtils;
import jakarta.validation.Valid;
import org.apache.commons.lang3.StringUtils;
import org.cupk2.base.domain.CupkUserContextLoader;
import org.cupk2.service.dto.SearchDto;
import org.cupk2.llm.service.LlmClientServiceInter;
import org.cupk2.service.lucene.doc.enums.DocumentTitleEnum;
import org.cupk2.service.lucene.doc.enums.IndexModelEnum;
import org.cupk2.zhzm.domain.ZhzmKnow;
import org.cupk2.zhzm.service.ZhzmKnowServiceInter;
import org.cupk2.tools.db.DataQuery;
import org.cupk2.tools.db.DataResult;
import org.cupk2.tools.db.ResultDataHandle;
import org.cupk2.tools.db.commons.DBRule;
import org.cupk2.tools.db.commons.DBSort;
import org.cupk2.tools.web.Cupk2HtmlUtils;
import org.cupk2.tools.web.CupkResponseCode;
import org.cupk2.tools.web.CupkResponseResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 知识
 *
 */
@RestController
@RequestMapping("/api/search")
public class WebSearchController {
    @Autowired
    private ZhzmKnowServiceInter zhzmKnowServiceImpl;
    @Autowired
    private LlmClientServiceInter llmClientServiceImpl;
    /**
     * 检索知识标题
     *
     * @return
     */
    @PreAuthorize("@cupkAction.has('search.title')")
    @PostMapping("/title")
    public CupkResponseResult searchTitle(@Valid @RequestBody SearchDto searchDto) {
        String searchType = getSearchType(searchDto);
        Cupk2LuceneSearchInter search = new Cupk2LuceneSearchImpl(CupkLuceneUtils.getLuceneIndexFilePath());
        DocumentQuery query = new DocumentQuery();
        query.setPageSize(10);
        query.setPage(searchDto.getPage());
        query.addRule(new DocumentRuleByMultiField(List.of(DocumentTitleEnum.title.name()), searchDto.getWord()));
        return CupkResponseResult.getInstance(CupkResponseCode.SUCESS, search.search(query));
    }





    /**
     * 全文检索知识
     *
     * @return
     */
    @PreAuthorize("@cupkAction.has('search.do')")
    @PostMapping
    public CupkResponseResult search(@Valid @RequestBody SearchDto searchDto) {
        String searchType = getSearchType(searchDto);
        Cupk2LuceneSearchInter search = new Cupk2LuceneSearchImpl(CupkLuceneUtils.getLuceneIndexFilePath());
        DocumentQuery query = new DocumentQuery();
        query.setPageSize(10);
        query.setPage(searchDto.getPage());
        if (searchDto.getModel() != null && !searchDto.getModel().equals("all")) {
            query.addRule(new DocumentRuleByTerm("model", searchDto.getModel()));
        }

        if (searchType.equals("EMBEDDING-ALL")) {
            query = new DocumentQuery();
            query.setPageSize(10);
            query.setPage(searchDto.getPage());
            search = new Cupk2LuceneSearchImpl(CupkLuceneUtils.getLuceneEmbeddingFilePath());
            query.addRule(new DocumentRuleByVector(DocumentTitleEnum.embedding_vector.name(), llmClientServiceImpl.getEmbeddingClient().getEmbedding(searchDto.getWord()), 30));
            DocumentResult result = search.search(query);
            return CupkResponseResult.getInstance(CupkResponseCode.SUCESS, loadViewImg(result));
        }

        if (searchType.equals("LUCENE-ALL")) {
            query.addRule(new DocumentRuleByMultiField(List.of(DocumentTitleEnum.title.name(), DocumentTitleEnum.tagTitles.name(), DocumentTitleEnum.text.name()), searchDto.getWord()));
            return CupkResponseResult.getInstance(CupkResponseCode.SUCESS, loadViewImg(search.search(query)));
        }
        if (searchType.equals("LUCENE-TAG")) {
            query.addRule(new DocumentRuleByMultiField(List.of(DocumentTitleEnum.tagTitles.name(), DocumentTitleEnum.tagKeys.name()), searchDto.getWord().split("\\|")[1] + "," + searchDto.getWord().split("\\|")[2]));
            return CupkResponseResult.getInstance(CupkResponseCode.SUCESS, loadViewImg(search.search(query)));
        }
        if (searchType.equals("MY")) {

            DataResult result = zhzmKnowServiceImpl.searchZhzmKnow(DataQuery.getInstance()//
                    .addRule(new DBRule("CUSERKEY", CupkUserContextLoader.getCurrentUserKey(), "="))//
                    .addSort(new DBSort("ETIME", DBSort.SORT_TYPE.DESC))
                    .setPage(searchDto.getPage()).setPageSize(10)//
            );
            DocumentResult myresult = new DocumentResult(result, getKnowToIndexDic());
            myresult = loadKnow(myresult);
            myresult.setSearchTitle("我的知识");
            loadViewImg(myresult);
            return CupkResponseResult.getInstance(CupkResponseCode.SUCESS, myresult);
        }
        if (searchType.equals("NEW")) {

            DataResult result = zhzmKnowServiceImpl.searchZhzmKnow(DataQuery.getInstance()//
                    .addSort(new DBSort("ETIME", DBSort.SORT_TYPE.DESC))
                    .setPage(searchDto.getPage()).setPageSize(10)//
            );
            DocumentResult myresult = new DocumentResult(result, getKnowToIndexDic());
            myresult = loadKnow(myresult);
            myresult.setSearchTitle("最新知识");
            loadViewImg(myresult);
            return CupkResponseResult.getInstance(CupkResponseCode.SUCESS, myresult);
        }
        return CupkResponseResult.getInstance(CupkResponseCode.ERROR, "无对应检索类型");
    }


    /**
     * 加载知识的预览图
     *
     * @param result
     * @return
     */
    private DocumentResult loadViewImg(DocumentResult result) {
        result.runDataHandle(new ResultDataHandle() {
            @Override
            public void handle(Map<String, Object> row) {
                String knowid = (String) row.get(DocumentTitleEnum.knowId.name());
                String model = (String) row.get(DocumentTitleEnum.model.name());
                if (model != null && (
                        model.equals(IndexModelEnum.KNOW_DOC.name())
                                || model.equals(IndexModelEnum.EMBEDDING.name())
                )) {
                    if (knowid != null) {
                        List<String> imgids = zhzmKnowServiceImpl.getImgView(knowid);
                        if (imgids.size() > 0) {
                            if (imgids.size() > 5) {
                                row.put(DocumentTitleEnum.imgs.name(), String.join(",", imgids.subList(0, 5)));
                            } else {
                                row.put(DocumentTitleEnum.imgs.name(), String.join(",", imgids));
                            }
                        }
                    }
                }
            }
        });
        return result;
    }


    private DocumentResult loadKnow(DocumentResult myresult) {
        myresult.runDataHandle(new ResultDataHandle() {
            @Override
            public void handle(Map<String, Object> row) {
                row.put("id", row.get("knowId"));
                row.put(DocumentTitleEnum.model.name(), IndexModelEnum.KNOW_DOC.name());
                String knowid = (String) row.get("knowId");
                if (StringUtils.isNotBlank(knowid)) {
                    ZhzmKnow know = zhzmKnowServiceImpl.getZhzmKnowById(knowid);
                    row.put(DocumentTitleEnum.text.name(), Cupk2HtmlUtils.getTextByHtml(zhzmKnowServiceImpl.getKnowText(know), 128));
                    row.put(DocumentTitleEnum.tagTitles.name(), zhzmKnowServiceImpl.getKnowIndexTags(know).getTitles());
                }
            }
        });
        return myresult;
    }

    private Map<String, String> getKnowToIndexDic() {
        Map<String, String> knowToIndexDic = new HashMap<>();

        knowToIndexDic.put("NONE", DocumentTitleEnum.fileId.name());



        knowToIndexDic.put("ID", DocumentTitleEnum.knowId.name());




        knowToIndexDic.put("TITLE", DocumentTitleEnum.title.name());
        knowToIndexDic.put("ETIME", DocumentTitleEnum.etime.name());





        knowToIndexDic.put("CUSERKEY", DocumentTitleEnum.userKey.name());

        knowToIndexDic.put("EUSERNAME", DocumentTitleEnum.userName.name());
        return knowToIndexDic;
    }


    /**
     * 获得检索类型
     *
     * @param searchDto
     * @return
     */
    private String getSearchType(SearchDto searchDto) {
        String type = "LUCENE-ALL";
        if ("EMBEDDING".equals(searchDto.getModel())) {
            return "EMBEDDING-ALL";
        }
        if (searchDto.getWord().trim().indexOf("T:") == 0 && searchDto.getWord().split("\\|").length == 3) {
            if (searchDto.getWord().split("\\|")[1].equals("SYS:MY_KNOW")) {

                type = "MY";
            } else if (searchDto.getWord().split("\\|")[1].equals("SYS:NEW_KNOW")) {

                type = "NEW";
            } else {
                type = "LUCENE-TAG";
            }
        } else {
            type = "LUCENE-ALL";
        }
        return type;
    }

}
